﻿namespace ElencySolutions.ImageMap
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Browser;
    using System.Windows.Controls;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;

    public partial class MainPage : UserControl
    {


        private Dictionary<int, ShapeAndPoints> _regionsAndPoints = new Dictionary<int, ShapeAndPoints>();

        private List<Point> _points = new List<Point>();
        private List<Shape> _temporaryShapes = new List<Shape>();
        private Polyline _temporaryPolyline;
        private Image _image;
        private ShapeType _currentShapeType = ShapeType.Polygon;
        private Key? _currentKey;
        private List<Shape> _shapes = new List<Shape>();
        private bool _draggingShape;
        private int _zIndex = 100;
        private bool _creating;
        private Shape _shapeBeingDragged;
        private Point _offset;
        private int _selectedShape = -1;
        private int _regionToScrollIntoView = -1;
        private int _hotSpotLeft;
        private int _hotSpotTop;
        private bool _headingsAdded;
        private const int INCREMENT = 30;

        public delegate void RedrawContentDelegate(int index, string url);
        public static event RedrawContentDelegate RedrawContent;

        public ShapeType CurrentShapeType
        {
            get { return _currentShapeType; }
            set { _currentShapeType = value; }
        }

        public MainPage()
        {
            InitializeComponent();
        }

        private void LayoutForHotSpots()
        {
            HeadingLabel.Content = "Hot Spot Editing";
            RedrawButton.Visibility = Visibility.Collapsed;
            CreateShapeButton.Visibility = Visibility.Collapsed;
            EllipseButton.Visibility = Visibility.Collapsed;
            RectangleButton.Visibility = Visibility.Collapsed;
            RegionsViewer.Visibility = Visibility.Collapsed;
            OKButton.Margin = new Thickness(12, OKButton.Margin.Top - 131, OKButton.Margin.Right, OKButton.Margin.Bottom);
            canvas1.Margin = new Thickness(canvas1.Margin.Left, canvas1.Margin.Top - 131, canvas1.Margin.Right, canvas1.Margin.Bottom);
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            InformationLabel.Visibility = System.Windows.Visibility.Collapsed;

            if (App.HotSpot)
            {
                LayoutForHotSpots();
            }

            RedrawContent += MainPage_RedrawContent;
            _image = new Image { Source = new BitmapImage(new Uri(App.ImageFile)) };
            _image.Stretch = Stretch.Fill;
            _image.Height = App.ImageHeight;
            _image.Width = App.ImageWidth;
            canvas1.MouseMove += canva1_MouseMove;
            canvas1.MouseLeave += canvas1_MouseLeave;
            _image.SetValue(Canvas.ZIndexProperty, _zIndex);
            _zIndex++;

            // change container height and width dependent on image size scrolling etc
            _image.SetValue(Canvas.LeftProperty, (double)0);
            _image.SetValue(Canvas.TopProperty, (double)0);
            canvas1.Children.Add(_image);

            int height = App.ImageHeight;
            int width = App.ImageWidth;

            if (width < 750)
                width = 750;

            //if (height < 600)
            //    height = 600;

            canvas1.Height = App.ImageHeight + 230;
            canvas1.Width = width;

            LayoutRoot.Height = canvas1.Height;
            LayoutRoot.Width = canvas1.Width + 30;

            DrawRegionsAndShapes();

            HtmlElement element = HtmlPage.Document.GetElementById("content");
            element.SetStyleAttribute("width", (LayoutRoot.Width) + "px");
            element.SetStyleAttribute("height", (LayoutRoot.Height) + "px");


            HtmlWindow parentWindow = HtmlPage.Window.GetProperty("opener") as HtmlWindow;

            if (parentWindow == null)
                return;

            HtmlDocument document = parentWindow.GetProperty("document") as HtmlDocument;

            if (document == null)
                return;            

            element = document.GetElementById(App.XmlValueId);
            string xml = HttpUtility.HtmlDecode(element.GetAttribute("value"));

            if (App.HotSpot)
            {
                string[] parts = xml.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                _hotSpotLeft = int.Parse(parts[0]) - 10;
                _hotSpotTop = int.Parse(parts[1]) - 10;

                _points.Add(new Point(_hotSpotLeft, _hotSpotTop));
                List<Point> newPoints = _points.ToList();
                _regionsAndPoints.Add(_regionsAndPoints.Count,
                          new ShapeAndPoints { Points = newPoints, ShapeType = ShapeType.Circle, Height = 20, Width = 20, Target = "Same window" });

                DrawRegionsAndShapes();
            }
            else
            {
                _regionsAndPoints = ImageMapHelper.LoadAreasXml(xml);
                DrawRegionsAndShapes();
            }
        }

        void MainPage_RedrawContent(int index, string url)
        {
            if (index > -1 && index < _regionsAndPoints.Count)
            {
                _regionsAndPoints[index].Url = url;
                DrawRegionsAndShapes();
            }
        }

        private void DrawPoints()
        {
            foreach (Shape shape in _temporaryShapes)
                canvas1.Children.Remove(shape);

            if (CurrentShapeType == ShapeType.Polygon)
            {
                for (int i = 0; i < _points.Count - 1; i++)
                {
                    Polyline polyline = new Polyline {Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1};
                    PointCollection polyPoints = new PointCollection {_points[i], _points[i + 1]};

                    polyline.Points = polyPoints;
                    polyline.SetValue(Canvas.ZIndexProperty, _zIndex);
                    _zIndex++;
                    _temporaryShapes.Add(polyline);
                    canvas1.Children.Add(polyline);
                }
            }
            else if (CurrentShapeType == ShapeType.Rectangle)
            {
                
            }
            else if (CurrentShapeType == ShapeType.Circle)
            {
                
            }
        }

        private void DrawPolygon(int region, ShapeAndPoints shapeAndPoints)
        {
            Polygon polygon = new Polygon { Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 };
            polygon.IsHitTestVisible = true;
            polygon.SetValue(Canvas.ZIndexProperty, _zIndex);
            _zIndex++;
            PointCollection polyPoints = new PointCollection();
            ShapeReference polygonShapeReference = new ShapeReference();
            polygonShapeReference.ShapeType = ShapeType.Polygon;
            polygonShapeReference.Shape = polygon;
            polygonShapeReference.ThePolygon = polygon;
            polygon.Tag = polygonShapeReference;

            for (int i = 0; i < shapeAndPoints.Points.Count; i++)
            {
                polyPoints.Add(shapeAndPoints.Points[i]);
                polygonShapeReference.PointIndexes.Add(i);
                polygonShapeReference.RegionId = region;

                Ellipse ellipse = new Ellipse
                                      {
                                          Stroke = new SolidColorBrush(Colors.Red),
                                          StrokeThickness = 1,
                                          Width = 10,
                                          Height = 10,
                                          Tag = string.Empty
                                      };

                polygonShapeReference.Ellipses.Add(ellipse);

                ellipse.SetLeft(shapeAndPoints.Points[i].X - 5);
                ellipse.SetTop(shapeAndPoints.Points[i].Y - 5);
                ellipse.SetValue(Canvas.ZIndexProperty, _zIndex);
                _zIndex++;
                ellipse.MouseLeftButtonDown += DragStart;
                ellipse.MouseLeftButtonUp += DragStop;
                ellipse.Fill = new SolidColorBrush(Colors.White);
                ellipse.Opacity = 0.7;

                if (_selectedShape != region)
                {
                    ellipse.Opacity = 0;
                    ellipse.StrokeThickness = 0;
                }

                _shapes.Add(ellipse);
                canvas1.Children.Add(ellipse);
                _regionsAndPoints[region].Shapes.Add(ellipse);

                ShapeReference shapeReference = new ShapeReference();
                shapeReference.ShapeType = ShapeType.EllipseMarker;
                shapeReference.Shape = polygon;
                shapeReference.PointIndexes.Add(i);
                shapeReference.RegionId = region;
                shapeReference.ThePolygon = polygon;
                ellipse.Tag = shapeReference;
            }

            polygon.Points = polyPoints;
            polygon.MouseLeftButtonDown += DragStart;
            polygon.MouseLeftButtonUp += DragStop;
            polygon.MouseMove += DragShape;
            polygon.Fill = new SolidColorBrush(Colors.White);
            polygon.Opacity = 0.4;
            polygon.MouseLeftButtonDown += DragStart;
            polygon.MouseLeftButtonUp += DragStop;

            _shapes.Add(polygon);
            canvas1.Children.Add(polygon);
            _regionsAndPoints[region].Shapes.Add(polygon);
        }

        private void DrawCircle(int region, ShapeAndPoints shapeAndPoints)
        {
            Ellipse circle = new Ellipse { Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 };
            circle.SetValue(Canvas.ZIndexProperty, _zIndex);
            _zIndex++;
            ShapeReference circleShapeReference = new ShapeReference();
            circleShapeReference.ShapeType = ShapeType.Circle;
            circleShapeReference.Shape = circle;
            circleShapeReference.Height = shapeAndPoints.Height;
            circleShapeReference.Width = shapeAndPoints.Width;
            circle.Tag = circleShapeReference;
            circle.IsHitTestVisible = true;

            circle.SetLeft(shapeAndPoints.Points[0].X);
            circle.SetTop(shapeAndPoints.Points[0].Y);
            circleShapeReference.RegionId = region;
            circle.Height = shapeAndPoints.Height;
            circle.Width = shapeAndPoints.Width;

            if (_selectedShape == region && !App.HotSpot)
            {
                Ellipse ellipse = new Ellipse
                                      {
                                          Stroke = new SolidColorBrush(Colors.Red),
                                          StrokeThickness = 1,
                                          Width = 10,
                                          Height = 10,
                                          Tag = string.Empty
                                      };

                circleShapeReference.Ellipses.Add(ellipse);

                ellipse.SetLeft(shapeAndPoints.Points[0].X + shapeAndPoints.Width - 5);
                ellipse.SetTop(shapeAndPoints.Points[0].Y + shapeAndPoints.Height - 5);
                ellipse.SetValue(Canvas.ZIndexProperty, _zIndex);
                _zIndex++;
                ellipse.MouseLeftButtonDown += DragStart;
                ellipse.MouseLeftButtonUp += DragStop;
                ellipse.Fill = new SolidColorBrush(Colors.White);
                ellipse.Opacity = 0.7;
                _shapes.Add(ellipse);
                canvas1.Children.Add(ellipse);
                _regionsAndPoints[region].Shapes.Add(ellipse);

                ShapeReference shapeReference = new ShapeReference();
                shapeReference.ShapeType = ShapeType.EllipseMarker;
                shapeReference.Shape = circle;
                shapeReference.PointIndexes.Add(0);
                shapeReference.RegionId = region;
                ellipse.Tag = shapeReference;
            }

            circle.MouseLeftButtonDown += DragStart;
            circle.MouseLeftButtonUp += DragStop;
            circle.MouseMove += DragShape;
            circle.Fill = new SolidColorBrush(Colors.White);
            circle.Opacity = 0.4;
            circle.MouseLeftButtonDown += DragStart;
            circle.MouseLeftButtonUp += DragStop;

            _shapes.Add(circle);
            canvas1.Children.Add(circle);
            _regionsAndPoints[region].Shapes.Add(circle);
        }

        private void DrawRectangle(int region, ShapeAndPoints shapeAndPoints)
        {
            Rectangle rectangle = new Rectangle { Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 };
            rectangle.SetValue(Canvas.ZIndexProperty, _zIndex);
            _zIndex++;
            ShapeReference rectangleShapeReference = new ShapeReference();
            rectangleShapeReference.ShapeType = ShapeType.Rectangle;
            rectangleShapeReference.Shape = rectangle;
            rectangleShapeReference.Height = shapeAndPoints.Height;
            rectangleShapeReference.Width = shapeAndPoints.Width;
            rectangle.Tag = rectangleShapeReference;

            rectangle.SetLeft(shapeAndPoints.Points[0].X);
            rectangle.SetTop(shapeAndPoints.Points[0].Y);
            rectangleShapeReference.RegionId = region;
            rectangle.Height = shapeAndPoints.Height;
            rectangle.Width = shapeAndPoints.Width;
            rectangle.IsHitTestVisible = true;

            if (_selectedShape == region)
            {
                Ellipse ellipse = new Ellipse
                                      {
                                          Stroke = new SolidColorBrush(Colors.Red),
                                          StrokeThickness = 1,
                                          Width = 10,
                                          Height = 10,
                                          Tag = string.Empty
                                      };

                rectangleShapeReference.Ellipses.Add(ellipse);

                ellipse.SetLeft(shapeAndPoints.Points[0].X + shapeAndPoints.Width - 5);
                ellipse.SetTop(shapeAndPoints.Points[0].Y + shapeAndPoints.Height - 5);
                ellipse.SetValue(Canvas.ZIndexProperty, _zIndex);
                _zIndex++;
                ellipse.MouseLeftButtonDown += DragStart;
                ellipse.MouseLeftButtonUp += DragStop;
                ellipse.Fill = new SolidColorBrush(Colors.White);
                ellipse.Opacity = 0.7;
                _shapes.Add(ellipse);
                canvas1.Children.Add(ellipse);
                _regionsAndPoints[region].Shapes.Add(ellipse);

                ShapeReference shapeReference = new ShapeReference();
                shapeReference.ShapeType = ShapeType.EllipseMarker;
                shapeReference.Shape = rectangle;
                shapeReference.PointIndexes.Add(0);
                shapeReference.RegionId = region;
                ellipse.Tag = shapeReference;
            }

            rectangle.MouseLeftButtonDown += DragStart;
            rectangle.MouseLeftButtonUp += DragStop;
            rectangle.MouseMove += DragShape;
            rectangle.Fill = new SolidColorBrush(Colors.White);
            rectangle.Opacity = 0.4;
            rectangle.MouseLeftButtonDown += DragStart;
            rectangle.MouseLeftButtonUp += DragStop;

            _shapes.Add(rectangle);
            canvas1.Children.Add(rectangle);
            _regionsAndPoints[region].Shapes.Add(rectangle);
        }

        private void DrawRegionsAndShapes()
        {
            //foreach (Shape control in _shapes)
            //    canvas1.Children.Remove(control);

            //RegionsAndShapesCanvas.Children.Clear();

            if (!_headingsAdded)
            {
                Label label = new Label();
                label.Content = "Region";
                RegionsAndShapesCanvas.Children.Add(label);
                label.SetValue(Canvas.TopProperty, 0D);
                label.SetValue(Canvas.LeftProperty, 0D);

                label = new Label();
                label.Content = "Shape";
                RegionsAndShapesCanvas.Children.Add(label);
                label.SetValue(Canvas.TopProperty, 0D);
                label.SetValue(Canvas.LeftProperty, 50D);

                label = new Label();
                label.Content = "Url";
                RegionsAndShapesCanvas.Children.Add(label);
                label.SetValue(Canvas.TopProperty, 0D);
                label.SetValue(Canvas.LeftProperty, 110D);

                label = new Label();
                label.Content = "Alt text";
                RegionsAndShapesCanvas.Children.Add(label);
                label.SetValue(Canvas.TopProperty, 0D);
                label.SetValue(Canvas.LeftProperty, 285D);

                label = new Label();
                label.Content = "Target";
                RegionsAndShapesCanvas.Children.Add(label);
                label.SetValue(Canvas.TopProperty, 0D);
                label.SetValue(Canvas.LeftProperty, 450D);

                Polyline polyline = new Polyline();
                polyline.Points.Add(new Point(0, 20D));
                polyline.Points.Add(new Point(1000, 20D));
                polyline.Stroke = new SolidColorBrush(Colors.Gray);
                polyline.StrokeThickness = 1;
                RegionsAndShapesCanvas.Children.Add(polyline);
                _headingsAdded = true;
            }

            double offset = -1;

            foreach (int region in _regionsAndPoints.Keys)
            {
                RegionsAndShapesCanvas.Height = (_regionsAndPoints.Keys.Count * INCREMENT) + INCREMENT;
                RegionsAndShapesGrid.Height = (_regionsAndPoints.Keys.Count * INCREMENT) + INCREMENT;
                double top = (region * INCREMENT) + INCREMENT;

                ShapeAndPoints shapeAndPoints = _regionsAndPoints[region];

                if (shapeAndPoints.Selected && _selectedShape != region)
                {
                    foreach (Shape shape in shapeAndPoints.ListViewObjects.Where(current => current.Tag != null && current.Tag.ToString() == "Highlighter").Cast<Shape>())
                        RegionsAndShapesCanvas.Children.Remove(shape);

                    foreach (Label currentLabel in shapeAndPoints.ListViewObjects.Where(current => current.Tag != null && current.Tag.ToString() == "InfoLabel").Cast<Label>())
                        currentLabel.Refresh();

                    shapeAndPoints.Selected = false;
                    shapeAndPoints.Valid = false;
                }

                if (shapeAndPoints.Valid && _selectedShape != region)
                    continue;

                RemoveExistingShapesForRegion(region);

                if (shapeAndPoints.ShapeType == ShapeType.Polygon)
                    DrawPolygon(region, shapeAndPoints);
                else if (shapeAndPoints.ShapeType == ShapeType.Circle)
                    DrawCircle(region, shapeAndPoints);
                else if (shapeAndPoints.ShapeType == ShapeType.Rectangle)
                    DrawRectangle(region, shapeAndPoints);

                if (region == _selectedShape)
                {
                    Rectangle rectangle = new Rectangle();
                    rectangle.Tag = "Highlighter";
                    rectangle.Fill = new SolidColorBrush(Colors.LightGray);
                    rectangle.Width = 1000;
                    rectangle.Height = INCREMENT;
                    RegionsAndShapesCanvas.Children.Add(rectangle);
                    rectangle.SetValue(Canvas.TopProperty, top);
                    _regionsAndPoints[region].ListViewObjects.Add(rectangle);
                }

                Label label = new Label();
                label.Name = "Region_" + Guid.NewGuid().ToString("N");
                label.Tag = "InfoLabel";
                label.Content = region.ToString();
                RegionsAndShapesCanvas.Children.Add(label);
                label.SetValue(Canvas.TopProperty, top + 7D);
                label.SetValue(Canvas.LeftProperty, 3D);
                _regionsAndPoints[region].ListViewObjects.Add(label);

                label = new Label();
                label.Tag = "InfoLabel";
                label.Content = shapeAndPoints.ShapeType.ToString();
                RegionsAndShapesCanvas.Children.Add(label);
                label.SetValue(Canvas.TopProperty, top + 7D);
                label.SetValue(Canvas.LeftProperty, 50D);
                _regionsAndPoints[region].ListViewObjects.Add(label);

                TextBox textBox = new TextBox();
                textBox.Name = "Url_" + Guid.NewGuid().ToString("N");
                textBox.Tag = region + "|url";
                textBox.Text = shapeAndPoints.Url;
                textBox.TextChanged += textBox_TextChanged;
                textBox.Width = 150;
                RegionsAndShapesCanvas.Children.Add(textBox);
                textBox.SetValue(Canvas.TopProperty, top + 3);
                textBox.SetValue(Canvas.LeftProperty, 110D);
                _regionsAndPoints[region].ListViewObjects.Add(textBox);


                Button button = new Button();
                button.Name = "UrlPicker_" + Guid.NewGuid().ToString("N");
                button.Tag = region;
                button.Content = "...";
                button.Click += PickUrl;
                RegionsAndShapesCanvas.Children.Add(button);
                button.SetValue(Canvas.TopProperty, top + 3);
                button.SetValue(Canvas.LeftProperty, 263D);
                _regionsAndPoints[region].ListViewObjects.Add(button);

                textBox = new TextBox();
                textBox.Name = "Alt_" + Guid.NewGuid().ToString("N");
                textBox.Tag = region + "|alt";
                textBox.Text = shapeAndPoints.AltText;
                textBox.TextChanged += textBox_TextChanged;
                textBox.Width = 150;
                RegionsAndShapesCanvas.Children.Add(textBox);
                textBox.SetValue(Canvas.TopProperty, top + 3);
                textBox.SetValue(Canvas.LeftProperty, 285D);
                _regionsAndPoints[region].ListViewObjects.Add(textBox);

                ComboBox combo = new ComboBox();
                combo.Name = "Target_" + Guid.NewGuid().ToString("N");
                combo.Tag = region;
                combo.Items.Add("Same window");
                combo.Items.Add("New window");
                combo.SelectedIndex = shapeAndPoints.Target == "Same window" ? 0 : 1;
                combo.Width = 120;
                combo.SelectionChanged += combo_SelectionChanged;
                RegionsAndShapesCanvas.Children.Add(combo);
                combo.SetValue(Canvas.TopProperty, top + 4D);
                combo.SetValue(Canvas.LeftProperty, 450D);
                _regionsAndPoints[region].ListViewObjects.Add(combo);

                button = new Button();
                button.Name = "Select_" + Guid.NewGuid().ToString("N");
                button.Tag = region;
                button.Content = "Select";
                button.Click += SelectRegion;
                RegionsAndShapesCanvas.Children.Add(button);
                button.SetValue(Canvas.TopProperty, top + 3);
                button.SetValue(Canvas.LeftProperty, 575D);
                _regionsAndPoints[region].ListViewObjects.Add(button);

                button = new Button();
                button.Name = "Delete_" + Guid.NewGuid().ToString("N");
                button.Tag = region;
                button.Content = "Delete";
                button.Click += DeleteRegion;
                RegionsAndShapesCanvas.Children.Add(button);
                button.SetValue(Canvas.TopProperty, top + 3);
                button.SetValue(Canvas.LeftProperty, 620D);
                _regionsAndPoints[region].ListViewObjects.Add(button);

                if (region == _regionToScrollIntoView)
                    offset = top;

                _regionsAndPoints[region].Valid = true;
            }


            if (offset != -1)
            {
                RegionsViewer.UpdateLayout();
                RegionsViewer.ScrollToVerticalOffset(offset);
            }

            _regionToScrollIntoView = -1;
        }

        private void PickUrl(object sender, RoutedEventArgs e)
        {
            CancelShapeCreation();
            Button button = sender as Button;
            _selectedShape = (int)button.Tag;
            _regionsAndPoints[_selectedShape].Selected = true;
            DrawRegionsAndShapes();

            HtmlElement element = HtmlPage.Document.GetElementById("CurrentUrl");
            element.SetProperty("value", _regionsAndPoints[_selectedShape].Url);
            element = HtmlPage.Document.GetElementById("Index");
            element.SetProperty("value", _selectedShape.ToString());
            HtmlPage.Window.CreateInstance("PickUrl");
        }

        private void combo_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            CancelShapeCreation();
            ComboBox combo = sender as ComboBox;
            int region = (int)combo.Tag;
            _regionsAndPoints[region].Target = combo.SelectedItem.ToString();
        }

        private void SelectRegion(object sender, RoutedEventArgs e)
        {
            CancelShapeCreation();
            Button button = sender as Button;
            _selectedShape = (int)button.Tag;
            _regionsAndPoints[_selectedShape].Selected = true;
            DrawRegionsAndShapes();
        }

        private void DeleteRegion(object sender, RoutedEventArgs e)
        {
            CancelShapeCreation();
            Button button = sender as Button;
            int region = (int)button.Tag;

            RemoveExistingShapesForRegion(region);

            foreach (var element in _regionsAndPoints[region].ListViewObjects)
                RegionsAndShapesCanvas.Children.Remove(element);


            _regionsAndPoints.Remove(region);

            // reset regions
            List<int> keys = _regionsAndPoints.Keys.Where(current => current > region).ToList();
            List<ShapeAndPoints> shapesAndPoints = keys.Select(key => _regionsAndPoints[key]).ToList();

            foreach (int key in keys)
                _regionsAndPoints.Remove(key);

            for (int i = 0; i < keys.Count(); i++)
                _regionsAndPoints.Add(keys[i] - 1, shapesAndPoints[i]);

            _selectedShape = -1;

            keys = _regionsAndPoints.Keys.Where(current => current >= region).ToList();

            // need to modify label and other tags
            foreach (int key in keys)
            {
                ShapeAndPoints shapeAndPoints = _regionsAndPoints[key];

                foreach (var element in shapeAndPoints.ListViewObjects)
                {
                    if (element is Shape)
                    {
                        Shape shape = element as Shape;
                        shape.SetTop(shape.GetTop() - INCREMENT);
                    }
                    else if (element is Control)
                    {
                        Control control = element as Control;

                        if (control.Name.Contains("_"))
                        {
                            string startWith = control.Name.Substring(0, control.Name.IndexOf("_"));

                            switch (startWith)
                            {
                                case "Region":
                                    ((Label)control).Content = key.ToString();
                                    break;
                                case "Url":
                                    control.Tag = key + "|url";
                                    break;
                                case "Alt":
                                    control.Tag = key + "|alt";
                                    break;
                                case "Combo":
                                case "Select":
                                case "Delete":
                                case "UrlPicker":
                                    control.Tag = key;
                                    break;
                            }
                        }

                        control.SetTop(control.GetTop() - INCREMENT);

                        if (control is Label)
                            ((Label)control).Refresh();

                    }
                }
            }
        }

        private void RemoveExistingShapesForRegion(int region)
        {
            foreach (Shape shape in _regionsAndPoints[region].Shapes)
                canvas1.Children.Remove(shape);

            _regionsAndPoints[region].Shapes.Clear();
        }

        void textBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            TextBox textBox = sender as TextBox;
            string[] parts = textBox.Tag.ToString().Split(new[] {'|'});
            int region = int.Parse(parts[0]);
            string property = parts[1];

            if (property == "url")
                _regionsAndPoints[region].Url = textBox.Text;

            if (property == "alt")
                _regionsAndPoints[region].AltText = textBox.Text;
        }

        private void DragPolygon(Point newPosition, ShapeReference shapeReference)
        {
            // dragging an ellipse of a polygon
            if (shapeReference.PointIndexes.Count == 1)
            {
                double xDifference = newPosition.X - _offset.X;
                double yDifference = newPosition.Y - _offset.Y;

                if (xDifference + 5 < 0)
                    xDifference = -5;

                if (xDifference + 5 > _image.Width)
                    xDifference = _image.Width - 5;

                if (yDifference + 5 < 0)
                    yDifference = -5;

                if (yDifference > _image.Height)
                    yDifference = _image.Height - 5;

                Point oldPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());

                _shapeBeingDragged.SetLeft(xDifference);
                _shapeBeingDragged.SetTop(yDifference);

                Point newPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());
                Polygon polygon = shapeReference.ThePolygon;

                int index = shapeReference.PointIndexes[0];
                _regionsAndPoints[shapeReference.RegionId].Points[index] = new Point(polygon.Points[index].X + (newPos.X - oldPos.X), polygon.Points[index].Y + (newPos.Y - oldPos.Y));
                polygon.Points[index] = new Point(polygon.Points[index].X + (newPos.X - oldPos.X), polygon.Points[index].Y + (newPos.Y - oldPos.Y));
                //////_regionsAndPoints[shapeReference.RegionId].Valid = false;
            }
            else // dragging the polygon
            {
                Point oldPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());
                _shapeBeingDragged.SetLeft(newPosition.X - _offset.X);
                _shapeBeingDragged.SetTop(newPosition.Y - _offset.Y);
                Point newPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());

                for (int i = 0; i < shapeReference.Ellipses.Count; i++)
                {
                    Ellipse ellipse = shapeReference.Ellipses[i];
                    Point oldPosition = new Point(ellipse.GetLeft(), ellipse.GetTop());
                    ellipse.SetLeft(oldPosition.X + (newPos.X - oldPos.X));
                    ellipse.SetTop(oldPosition.Y + (newPos.Y - oldPos.Y));
                    _regionsAndPoints[shapeReference.RegionId].Points[i] = new Point(ellipse.GetLeft() + 5, ellipse.GetTop() + 5);
                }

                // get min and max x coodinates
                double minX = shapeReference.Ellipses.Select(current => current.GetLeft() + 5).Min(current => current);
                double maxX = shapeReference.Ellipses.Select(current => current.GetLeft() + 5).Max(current => current);
                double minY = shapeReference.Ellipses.Select(current => current.GetTop() + 5).Min(current => current);
                double maxY = shapeReference.Ellipses.Select(current => current.GetTop() + 5).Max(current => current);
                double? xDifference = null;
                double? yDifference = null;

                if (minX < 0)
                    xDifference = Math.Abs(minX);

                if (maxX > _image.Width)
                    xDifference = Math.Abs(maxX - _image.Width) * (-1);

                if (minY < 0)
                    yDifference = Math.Abs(minY);

                if (maxY > _image.Height)
                    yDifference = Math.Abs(maxY - _image.Height) * (-1);

                if (xDifference.HasValue)
                {
                    Polygon polygon = _shapeBeingDragged as Polygon;

                    for (int i = 0; i < polygon.Points.Count; i++)
                    {
                        Point point = polygon.Points[i];
                        polygon.Points[i] = new Point(point.X + xDifference.Value, point.Y);
                        Ellipse ellipse = shapeReference.Ellipses[i];
                        ellipse.SetLeft(ellipse.GetLeft() + xDifference.Value);
                        _regionsAndPoints[shapeReference.RegionId].Points[i] = new Point(ellipse.GetLeft() + 5, ellipse.GetTop() + 5);
                    }
                }

                if (yDifference.HasValue)
                {
                    Polygon polygon = _shapeBeingDragged as Polygon;

                    for (int i = 0; i < polygon.Points.Count; i++)
                    {
                        Point point = polygon.Points[i];
                        polygon.Points[i] = new Point(point.X, point.Y + yDifference.Value);
                        Ellipse ellipse = shapeReference.Ellipses[i];
                        ellipse.SetTop(ellipse.GetTop() + yDifference.Value);
                        _regionsAndPoints[shapeReference.RegionId].Points[i] = new Point(ellipse.GetLeft() + 5, ellipse.GetTop() + 5);
                    }
                }

                ////_regionsAndPoints[shapeReference.RegionId].Valid = false;
            }
        }

        private void DragCircle(Point newPosition, ShapeReference shapeReference)
        {
            if (shapeReference.ShapeType == ShapeType.EllipseMarker)
            {
                double xDifference = newPosition.X - _offset.X;
                double yDifference = newPosition.Y - _offset.Y;

                _shapeBeingDragged.SetLeft(xDifference);
                _shapeBeingDragged.SetTop(yDifference);

                Point newPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());
                Ellipse ellipse = shapeReference.Shape as Ellipse;

                double width = newPos.X - ellipse.GetLeft() + 5;
                double height = newPos.Y - ellipse.GetTop() + 5;

                if (width <= 0)
                    width = 2;

                if (height <= 0)
                    height = 2;

                if (width < height)
                    height = width;

                if (height < width)
                    width = height;

                if ((ellipse.GetLeft() + width) > (_image.Width + 1))
                    width -= (ellipse.GetLeft() + width - _image.Width);

                if ((ellipse.GetTop() + height) > (_image.Height + 1))
                    height -= (ellipse.GetTop() + height - _image.Height);

                if (width < height)
                    height = width;

                if (height < width)
                    width = height;

                _regionsAndPoints[shapeReference.RegionId].Width = width;
                _regionsAndPoints[shapeReference.RegionId].Height = height;

                shapeReference.Width = width;
                shapeReference.Height = height;
                ellipse.Height = height;
                ellipse.Width = width;

                _shapeBeingDragged.SetLeft(_regionsAndPoints[shapeReference.RegionId].Points[0].X + width - 5);
                _shapeBeingDragged.SetTop(_regionsAndPoints[shapeReference.RegionId].Points[0].Y + height - 5);
                ////_regionsAndPoints[shapeReference.RegionId].Valid = false;
            }
            else
            {
                Point oldPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());

                double xPosition = newPosition.X - _offset.X;
                double yPosition = newPosition.Y - _offset.Y;

                if (xPosition < (-1 - (App.HotSpot ? 10 : 0)))
                    xPosition = App.HotSpot ? -10 : 0;

                if (yPosition < (-1 - (App.HotSpot ? 10 : 0)))
                    yPosition = App.HotSpot ? -10 : 0;

                Ellipse circle = _shapeBeingDragged as Ellipse;

                if (xPosition + circle.Width > (_image.Width + 1) + (App.HotSpot ? 10 : 0))
                    xPosition = (_image.Width - circle.Width) + (App.HotSpot ? 10 : 0);

                if (yPosition + circle.Height > (_image.Height + 1) + (App.HotSpot ? 10 : 0))
                    yPosition = (_image.Height - circle.Height) + (App.HotSpot ? 10 : 0);

                _shapeBeingDragged.SetLeft(xPosition);
                _shapeBeingDragged.SetTop(yPosition);

                Point newPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());
                _regionsAndPoints[shapeReference.RegionId].Points[0] = new Point(xPosition, yPosition);

                if (!App.HotSpot)
                {
                    for (int i = 0; i < shapeReference.Ellipses.Count; i++)
                    {
                        Ellipse ellipse = shapeReference.Ellipses[i];
                        Point oldPosition = new Point(ellipse.GetLeft(), ellipse.GetTop());
                        ellipse.SetLeft(oldPosition.X + (newPos.X - oldPos.X));
                        ellipse.SetTop(oldPosition.Y + (newPos.Y - oldPos.Y));
                    }
                }
                
                ////_regionsAndPoints[shapeReference.RegionId].Valid = false;
            }
        }

        private void DragRectangle(Point newPosition, ShapeReference shapeReference)
        {
            if (shapeReference.ShapeType == ShapeType.EllipseMarker)
            {
                double xDifference = newPosition.X - _offset.X;
                double yDifference = newPosition.Y - _offset.Y;

                _shapeBeingDragged.SetLeft(xDifference);
                _shapeBeingDragged.SetTop(yDifference);

                Point newPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());
                Rectangle rectangle = shapeReference.Shape as Rectangle;

                double width = newPos.X - rectangle.GetLeft() + 5;
                double height = newPos.Y - rectangle.GetTop() + 5;
                
                if (width <= 0)
                    width = 2;

                if (height <= 0)
                    height = 2;

                if ((rectangle.GetLeft() + width) > (_image.Width + 1))
                    width -= (rectangle.GetLeft() + width - _image.Width);

                if ((rectangle.GetTop() + height) > (_image.Height + 1))
                    height -= (rectangle.GetTop() + height - _image.Height);

                _regionsAndPoints[shapeReference.RegionId].Width = width;
                _regionsAndPoints[shapeReference.RegionId].Height = height;

                shapeReference.Width = width;
                shapeReference.Height = height;
                rectangle.Height = height;
                rectangle.Width = width;

                _shapeBeingDragged.SetLeft(_regionsAndPoints[shapeReference.RegionId].Points[0].X + width - 5);
                _shapeBeingDragged.SetTop(_regionsAndPoints[shapeReference.RegionId].Points[0].Y + height - 5);
                ////_regionsAndPoints[shapeReference.RegionId].Valid = false;
            }
            else
            {
                Point oldPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());

                double xPosition = newPosition.X - _offset.X;
                double yPosition = newPosition.Y - _offset.Y;

                if (xPosition < -1)
                    xPosition = 0;

                if (yPosition < -1)
                    yPosition = 0;

                Rectangle rectangle = _shapeBeingDragged as Rectangle;

                if (xPosition + rectangle.Width > (_image.Width + 1))
                    xPosition = _image.Width - rectangle.Width;

                if (yPosition + rectangle.Height > (_image.Height + 1))
                    yPosition = _image.Height - rectangle.Height;

                _shapeBeingDragged.SetLeft(xPosition);
                _shapeBeingDragged.SetTop(yPosition);

                Point newPos = new Point(_shapeBeingDragged.GetLeft(), _shapeBeingDragged.GetTop());
                _regionsAndPoints[shapeReference.RegionId].Points[0] = new Point(xPosition, yPosition);

                for (int i = 0; i < shapeReference.Ellipses.Count; i++)
                {
                    Ellipse ellipse = shapeReference.Ellipses[i];
                    Point oldPosition = new Point(ellipse.GetLeft(), ellipse.GetTop());
                    ellipse.SetLeft(oldPosition.X + (newPos.X - oldPos.X));
                    ellipse.SetTop(oldPosition.Y + (newPos.Y - oldPos.Y));
                }

                ////_regionsAndPoints[shapeReference.RegionId].Valid = false;
            }
        }

        private void DragShape(object sender, MouseEventArgs e)
        {
            if (!_draggingShape || _shapeBeingDragged == null)
                return;

            CancelShapeCreation();
            Point newPosition = e.GetPosition(canvas1);
            ShapeReference shapeReference = _shapeBeingDragged.Tag as ShapeReference;

            if (shapeReference.Shape is Polygon)
                DragPolygon(newPosition, shapeReference);
            else if (shapeReference.Shape is Rectangle)
                DragRectangle(newPosition, shapeReference);
            else if (shapeReference.Shape is Ellipse)
                DragCircle(newPosition, shapeReference);
        }

        private void DragStop(object sender, MouseButtonEventArgs e)
        {
            Shape shape = sender as Shape;
            _draggingShape = false;
            _image.ReleaseMouseCapture();
            _shapeBeingDragged = null;
            DrawRegionsAndShapes();
        }

        private void DragStart(object sender, MouseButtonEventArgs e)
        {
            Shape shape = sender as Shape;

            if (shape == null || shape.Tag == null)
            {
                _selectedShape = -1;
                return;
            }

            ShapeReference shapeReference = shape.Tag as ShapeReference;
            _selectedShape = shapeReference.RegionId;
            _regionsAndPoints[_selectedShape].Selected = true;
            _regionToScrollIntoView = shapeReference.RegionId;

            _image.CaptureMouse();
            _draggingShape = true;
            _shapeBeingDragged = shape;
            _offset = e.GetPosition(shape);
        }

        private void canvas1_MouseLeave(object sender, MouseEventArgs e)
        {
            //_draggingShape = false;
            //DrawRegionsAndShapes();
        }

        private void canva1_MouseMove(object sender, MouseEventArgs e)
        {
            if (_draggingShape)
                DragShape(null, e);

            if (!_creating)
                return;

            if (_points.Count == 0)
                return;

            StylusPointCollection points = e.StylusDevice.GetStylusPoints(_image);

            if (CurrentShapeType == ShapeType.Polygon)
            {
                DrawPoints();

                if (_temporaryPolyline != null)
                    canvas1.Children.Remove(_temporaryPolyline);

                _temporaryPolyline = new Polyline { Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 };
                PointCollection polyPoints = new PointCollection {_points.Last(), new Point(points[0].X, points[0].Y) };
                _temporaryPolyline.Points = polyPoints;
                _temporaryPolyline.SetValue(Canvas.ZIndexProperty, _zIndex);
                _zIndex++;

                canvas1.Children.Add(_temporaryPolyline);
            }
            else if (CurrentShapeType == ShapeType.Rectangle)
            {
                DrawPoints();

                Rectangle rectangle = new Rectangle { Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 };
                rectangle.SetValue(Canvas.ZIndexProperty, _zIndex);
                _zIndex++;
                rectangle.SetLeft(_points[0].X);
                rectangle.SetTop(_points[0].Y);

                double width = points[0].X - _points[0].X;
                double height = points[0].Y - _points[0].Y;

                if (height < 0)
                    height = 2;

                if (width < 0)
                    width = 2;

                rectangle.Height = height;
                rectangle.Width = width;
                _temporaryShapes.Add(rectangle);
                canvas1.Children.Add(rectangle);
            }
            else if (CurrentShapeType == ShapeType.Circle)
            {
                DrawPoints();

                Ellipse ellipse = new Ellipse { Stroke = new SolidColorBrush(Colors.Red), StrokeThickness = 1 };
                ellipse.SetValue(Canvas.ZIndexProperty, _zIndex);
                _zIndex++;

                ellipse.SetLeft(_points[0].X);
                ellipse.SetTop(_points[0].Y);

                double width = points[0].X - _points[0].X;
                double height = points[0].Y - _points[0].Y;

                if (height < 0)
                    height = 2;

                if (width < 0)
                    width = 2;

                if (height < width)
                    width = height;

                if (width < height)
                    height = width;

                ellipse.Height = height;
                ellipse.Width = width;
                _temporaryShapes.Add(ellipse);
                canvas1.Children.Add(ellipse);
            }
        }

        private void canvas1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (!_creating)
                return;

            _selectedShape = -1;
            StylusPointCollection points = e.StylusDevice.GetStylusPoints(_image);

            if (_currentShapeType == ShapeType.Polygon)
            {
                InformationLabel.Visibility = Visibility.Visible;
                _points.Add(new Point(points[0].X, points[0].Y));

                if (_currentKey == Key.Shift)
                {
                    InformationLabel.Visibility = Visibility.Collapsed;

                    List<Point> newPoints = _points.ToList();

                    _regionsAndPoints.Add(_regionsAndPoints.Count, new ShapeAndPoints { Points = newPoints, ShapeType = CurrentShapeType, Target = "Same window" });
                    _points.Clear();
                    _selectedShape = _regionsAndPoints.Count - 1;
                    _regionsAndPoints[_selectedShape].Selected = true;
                    _regionToScrollIntoView = _selectedShape;
                    DrawRegionsAndShapes();
                    RemoveTemporaryShapes();
                    _creating = false;
                }
            }
            else if (_currentShapeType == ShapeType.Circle)
            {
                InformationLabel.Visibility = Visibility.Collapsed;

                _points.Add(new Point(points[0].X, points[0].Y));
                List<Point> newPoints = _points.ToList();

                if (newPoints.Count == 2)
                {
                    double width = newPoints[1].X - newPoints[0].X;
                    double height = newPoints[1].Y - newPoints[0].Y;

                    if (width < 0 || height < 0)
                    {
                        _points.Clear();
                        _creating = false;
                    }

                    // make sure width and height haven't come out of bounds, then maintain aspect
                    if (_points[0].X + width > _image.Width)
                        width = _image.Width - _points[0].X;

                    if (_points[0].Y + height > _image.Height)
                        height = _image.Height - _points[0].Y;

                    if (width < height)
                        height = width;

                    if (height < width)
                        width = height;

                    _regionsAndPoints.Add(_regionsAndPoints.Count,
                          new ShapeAndPoints { Points = newPoints, ShapeType = CurrentShapeType, Height = height, Width = width, Target = "Same window" });

                    _points.Clear();
                    _selectedShape = _regionsAndPoints.Count - 1;
                    _regionsAndPoints[_selectedShape].Selected = true;
                    _regionToScrollIntoView = _selectedShape;
                    DrawRegionsAndShapes();
                    RemoveTemporaryShapes();
                    _creating = false;
                }
            }
            else if (_currentShapeType == ShapeType.Rectangle)
            {
                InformationLabel.Visibility = Visibility.Collapsed;
                _points.Add(new Point(points[0].X, points[0].Y));
                List<Point> newPoints = _points.ToList();

                if (newPoints.Count == 2)
                {
                    double width = newPoints[1].X - newPoints[0].X;
                    double height = newPoints[1].Y - newPoints[0].Y;

                    if (width < 0 || height < 0)
                    {
                        _points.Clear();
                        _creating = false;
                    }

                    _regionsAndPoints.Add(_regionsAndPoints.Count,
                          new ShapeAndPoints { Points = newPoints, ShapeType = CurrentShapeType, Height = height, Width = width, Target = "Same window" });

                    _points.Clear();
                    _selectedShape = _regionsAndPoints.Count - 1;
                    _regionsAndPoints[_selectedShape].Selected = true;
                    _regionToScrollIntoView = _selectedShape;
                    DrawRegionsAndShapes();
                    RemoveTemporaryShapes();
                    _creating = false;
                }
            }

            DrawPoints();
        }

        private void RemoveTemporaryShapes()
        {
            foreach (Shape polyline in _temporaryShapes)
                canvas1.Children.Remove(polyline);

            if (_temporaryPolyline != null)
                canvas1.Children.Remove(_temporaryPolyline);
        }

        private void UserControl_KeyDown(object sender, KeyEventArgs e)
        {
            _currentKey = e.Key;
        }

        private void UserControl_KeyUp(object sender, KeyEventArgs e)
        {
            _currentKey = null;
        }

        private void canvas1_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _draggingShape = false;
            DrawRegionsAndShapes();
        }

        private void CreateShapeButton_Click(object sender, RoutedEventArgs e)
        {
            CancelShapeCreation();
            _creating = true;
            _currentShapeType = ShapeType.Polygon;
        }

        private void EllipseButton_Click(object sender, RoutedEventArgs e)
        {
            CancelShapeCreation();
            _creating = true;
            _currentShapeType = ShapeType.Circle;
        }

        private void RectangleButton_Click(object sender, RoutedEventArgs e)
        {
            CancelShapeCreation();
            _creating = true;
            _currentShapeType = ShapeType.Rectangle;
        }

        private void RedrawButton_Click(object sender, RoutedEventArgs e)
        {
            CancelShapeCreation();
            ImageMap imageMap = new ImageMap();
            imageMap.ImageAltText = App.ImageAltText;
            imageMap.ImageUrl = App.ImageFile;
            imageMap.ImageWidth = App.ImageWidth;
            imageMap.ImageHeight = App.ImageHeight;
            imageMap.DefaultLinkUrl = App.DefaultLinkUrl;

            imageMap.Areas.AddRange(ImageMapHelper.GetAreas(_regionsAndPoints));

            HtmlElement element = HtmlPage.Document.GetElementById("imageMapPreview");

            element.SetProperty("innerHTML", imageMap.GetHtml(string.Empty, true));
            HtmlPage.Window.CreateInstance("ShowInfoBox");
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            string xml = string.Empty;

            if (!App.HotSpot)
                xml = ImageMapHelper.GetAreaXml(_regionsAndPoints);
            else
                xml = string.Format("{0}|{1}", _regionsAndPoints[0].Points[0].X + 10, _regionsAndPoints[0].Points[0].Y + 10);
            
            // get parent window, try catch
            HtmlWindow parentWindow = HtmlPage.Window.GetProperty("opener") as HtmlWindow;

            if (parentWindow == null)
                return;

            HtmlDocument document = parentWindow.GetProperty("document") as HtmlDocument;

            if (document == null)
                return;

            HtmlElement element = document.GetElementById(App.XmlValueId);
            element.SetAttribute("value", HttpUtility.HtmlEncode(xml));


            if (App.HotSpot)
            {
                string leftText = HtmlPage.Document.GetElementById("LeftText").GetAttribute("value");
                string topText = HtmlPage.Document.GetElementById("TopText").GetAttribute("value");

                element = document.GetElementById(App.InfoBoxId);
                element.SetAttribute("value", string.Format("{0}: {1}px, {2}: {3}px", leftText, _regionsAndPoints[0].Points[0].X + 10, topText, _regionsAndPoints[0].Points[0].Y + 10));
            }

            HtmlPage.Window.CreateInstance("CloseWindow");
        }

        private void CancelShapeCreation()
        {
            InformationLabel.Visibility = Visibility.Collapsed;
            _creating = false;
            _points.Clear();
            RemoveTemporaryShapes();
        }

        [ScriptableMember]
        public void UrlChanged(string index, string url)
        {
            int indexPosition = int.Parse(index);

            if (RedrawContent != null)
                RedrawContent(indexPosition, url);
        }


    }
}
